package top.ed333.mcplugins.configurableevents.handler;

import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.event.Event;
import org.bukkit.event.EventPriority;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import top.ed333.mcplugins.configurableevents.ConsoleSender;
import top.ed333.mcplugins.configurableevents.action.Action;
import top.ed333.mcplugins.configurableevents.action.ActionManager;
import top.ed333.mcplugins.configurableevents.action.Actions;
import top.ed333.mcplugins.configurableevents.requirement.ReqGroup;
import top.ed333.mcplugins.configurableevents.requirement.ReqGroupManager;
import top.ed333.mcplugins.configurableevents.requirement.ReqGroups;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

public class HandlerManager {
    private static Handlers handlers = null;

    public static void initHandlers(File[] handlerCfgFiles) {
        List<Handler> handlerList = new ArrayList<>();
        for (File file : handlerCfgFiles) {
            YamlConfiguration handlerCfg = YamlConfiguration.loadConfiguration(file);
            String handlerName = handlerCfg.getString("name", null);
            String usePackage = handlerCfg.getString("usePackage", null);
            String eventName = handlerCfg.getString("eventName", null);
            String priority_bukkit = handlerCfg.getString("priority_bukkit", "NORMAL");
            ConfigurationSection requirementSec = handlerCfg.getConfigurationSection("requirement");
            ConfigurationSection actionsSec = handlerCfg.getConfigurationSection("actions");

            // check null
            if (handlerName == null || usePackage == null || eventName == null){
                ConsoleSender.err("&chandler 配置 '{0}' 中缺少必要的配置项, 请检查下列配置项是否存在: name, usePackage, eventName");
                continue;
            }

            // pkg
            String pkgName = PkgManager.packageFromName(usePackage);
            if (pkgName == null) {
                ConsoleSender.err("&c错误的事件包引用于 handler 配置中, handler: {0}, usePackage: {1}", handlerName, usePackage);
                continue;
            }

            // event class
            String className = pkgName + "." + eventName;
            Class<? extends Event> eventClass;
            try {
                Class<?> clazz = Class.forName(className);
                if (Event.class.isAssignableFrom(clazz)) {
                    eventClass = (Class<? extends Event>) clazz;
                } else {
                    ConsoleSender.err("&c所引用的类并非事件类! 位于 handler: '{0}', 将要引用的事件类: {1}", handlerName, className);
                    continue;
                }
            } catch (ClassNotFoundException e) {
                ConsoleSender.err("&c无法找到对应的事件类, 可能是引用的事件包或事件名拼写错误. 位于 handler: '{0}', 将要引用的事件类: {1}", handlerName, className);
                continue;
            }

            // priority
            EventPriority priority = EventPriority.NORMAL;
            try {
                priority = EventPriority.valueOf(priority_bukkit);
            } catch (IllegalArgumentException e) {
                ConsoleSender.warn("&chandler 配置 '{0}' 中配置了错误的优先级 '{1}', 将使用默认设置." ,handlerName, priority_bukkit);
            }

            // load requirements
            ReqGroups reqGroups = null;
            if (requirementSec != null) {
                List<ReqGroup> reqGroupList = new ArrayList<>();
                List<String> orTypes = requirementSec.getStringList("types.or");
                List<String> andTypes = requirementSec.getStringList("types.and");
                for (String key : requirementSec.getKeys(false)) {
                    if (key.equals("types")) continue;

                    ConfigurationSection groupSec = requirementSec.getConfigurationSection(key);
                    String reqName = groupSec.getString("reqName");
                    Object ext = groupSec.get("ext");

                    if (reqName == null || ext == null) {
                        ConsoleSender.err("&chandler 配置 '{0}' 中未正确配置 '{1}' 条件组, 将忽略该条件组.", handlerName, key);
                        continue;
                    }

                    ReqGroup group = ReqGroupManager.getByNameAndExt(key, reqName, ext);
                    if (group != null) {
                        reqGroupList.add(group);
                    } else {
                        ConsoleSender.warn("未知的条件名称 '{0}'，位于 handler '{1}' 中的条件组 '{2}'", reqName, handlerName, key);
                    }
                }
                reqGroups = new ReqGroups(reqGroupList, orTypes, andTypes);
            }

            // load actions
            Actions actions = null;
            if (actionsSec != null) {
                List<Action> actionList = new ArrayList<>();
                actionsSec.getValues(false).forEach((actionName, val) -> {
                    Action action = ActionManager.getActionByName(actionName, val);
                    if (action != null) {
                        actionList.add(action);
                    } else {
                        ConsoleSender.warn("未知的执行动作 '{0}'，位于 handler '{1}' 中", actionName, handlerName);
                    }
                });
                actions = new Actions(actionList);
            }

            Handler handler = new HandlerImpl(handlerName, usePackage, eventName, priority, reqGroups, actions, eventClass);
            handlerList.add(handler);
        }
        handlers = new Handlers(handlerList);
    }

    public static Handlers getHandlers() {
        return handlers;
    }

    public static int getLoadedHandlerCount() {
        return handlers.size();
    }

    public static @Nullable Handler handlerFromName(@NotNull String name) {
        for (Handler handler : handlers) {
            if (handler.name().equals(name)) {
                return handler;
            }
        }
        return null;
    }
}
